﻿using Artizan.Iot.Hub.Mqtt.Server.Etos;
using MQTTnet.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Artizan.Iot.Hub.Mqtt.Topics;
using MQTTnet;
using Microsoft.Extensions.Logging;

namespace Artizan.Iot.Hub.Mqtt.Server
{
    [ExposeServices(typeof(IMqttPublishingService), typeof(IMqttService))]
    public class MqttPublishingService : MqttServiceBase, IMqttPublishingService, ISingletonDependency
    {
        private readonly ILogger<MqttPublishingService> _logger;
        private readonly IDistributedEventBus _distributedEventBus;

        public MqttPublishingService(
            ILogger<MqttPublishingService> logger,
            IDistributedEventBus distributedEventBus)
           : base()
        {
            _logger = logger;
            _distributedEventBus = distributedEventBus;
        }

        public override void ConfigureMqttServer(MqttServer mqttServer)
        {
            base.ConfigureMqttServer(mqttServer);

            MqttServer.InterceptingPublishAsync += InterceptingPublishHandlerAsync;
        }

        private async Task InterceptingPublishHandlerAsync(InterceptingPublishEventArgs eventArgs)
        {
            var topic = eventArgs.ApplicationMessage.Topic;

            _logger.LogDebug($"'{eventArgs.ClientId}' published '{eventArgs.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload ?? new byte[0])}'");

            #region TODO：根据ClientId，用户等判断是能发布这种主题 等具体的业务逻辑，慢慢规划

            /// TDOD
            if (topic == "not_allowed_topic") // TODO:
            {
                eventArgs.ProcessPublish = false;
                eventArgs.CloseConnection = true;
            }

            if (MqttTopicFilterComparer.Compare(eventArgs.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#") == MqttTopicFilterCompareResult.IsMatch)
            {
                // Replace the payload with the timestamp. But also extending a JSON 
                // based payload with the timestamp is a suitable use case.
                eventArgs.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O"));
            } 
            #endregion

            // TODO:根据ClientId, 判断是否有权限去发布主题
            if (MqttTopicHelper.IsSystemTopic(topic))
            {
                if (!MqttTopicHelper.IsBrokerItself(eventArgs.ClientId))
                {
                    // 客户端要发布系统主题，不接受，而是由系统执行系统主题的发布
                    // await _mqttInternalService.ExecuteSystemCommandAsync(context);
                    eventArgs.ProcessPublish = false;
                    return;
                }
            }
            else
            {
                if (!eventArgs.SessionItems.Contains(topic))
                {
                    var payloadString = Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload);
                    eventArgs.SessionItems.Add(eventArgs.ApplicationMessage.Topic, eventArgs.ApplicationMessage.Payload);
                }
                else
                {
                    var retainPayload = (byte[])eventArgs.SessionItems[eventArgs.ApplicationMessage.Topic];
                    if (!retainPayload.SequenceEqual(eventArgs.ApplicationMessage.Payload))
                    {
                    }
                }
            }

            if (eventArgs.ProcessPublish)
            {
                await _distributedEventBus.PublishAsync(
                   new ClientPublishTopicEto
                   {
                       ClientId = eventArgs.ClientId,
                       Topic = eventArgs.ApplicationMessage.Topic,
                       Payload = eventArgs.ApplicationMessage.Payload
                   }
                );
            }
        }
    }
}
